function LoadingManager(onLoad, onProgress, onError) {
  const scope = this

  let isLoading = false
  let itemsLoaded = 0
  let itemsTotal = 0
  let urlModifier = undefined
  const handlers = []

  // Refer to #5689 for the reason why we don't set .onStart
  // in the constructor

  this.onStart = undefined
  this.onLoad = onLoad
  this.onProgress = onProgress
  this.onError = onError

  this.itemStart = function (url) {
    itemsTotal++

    if (isLoading === false) {
      if (scope.onStart !== undefined) {
        scope.onStart(url, itemsLoaded, itemsTotal)
      }
    }

    isLoading = true
  }

  this.itemEnd = function (url) {
    itemsLoaded++

    if (scope.onProgress !== undefined) {
      scope.onProgress(url, itemsLoaded, itemsTotal)
    }

    if (itemsLoaded === itemsTotal) {
      isLoading = false

      if (scope.onLoad !== undefined) {
        scope.onLoad()
      }
    }
  }

  this.itemError = function (url) {
    if (scope.onError !== undefined) {
      scope.onError(url)
    }
  }

  this.resolveURL = function (url) {
    if (urlModifier) {
      return urlModifier(url)
    }

    return url
  }

  this.setURLModifier = function (transform) {
    urlModifier = transform

    return this
  }

  this.addHandler = function (regex, loader) {
    handlers.push(regex, loader)

    return this
  }

  this.removeHandler = function (regex) {
    const index = handlers.indexOf(regex)

    if (index !== -1) {
      handlers.splice(index, 2)
    }

    return this
  }

  this.getHandler = function (file) {
    for (let i = 0, l = handlers.length; i < l; i += 2) {
      const regex = handlers[i]
      const loader = handlers[i + 1]

      if (regex.global) regex.lastIndex = 0 // see #17920

      if (regex.test(file)) {
        return loader
      }
    }

    return null
  }
}

const DefaultLoadingManager = new LoadingManager()

export {DefaultLoadingManager, LoadingManager}
